home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
VideoToolbox 96.06.15
/
VideoToolboxSources
/
GDOpenWindow.c
< prev
next >
Wrap
Text File
|
1996-03-08
|
18KB
|
409 lines
/* GDOpenWindow.c
Copyright © 1989-1995 Denis G. Pelli
EXAMPLE:
Open your window by saying:
window=GDOpenWindow(device);
When you're through with the window, get rid of it by calling:
GDDisposeWindow(window);
Besides closing the window and disposing of the allocated memory structures
GDDisposeWindow also restores the device's color table and clut.
SUMMARY:
window=GDOpenWindow(device) opens a full-screen window on the specified screen,
call GDGrayColorTable(device) which gives the device a standard gray color table
(if it doesn't already), and calls AddExplicitPalette(window), which allows you
to specify colors to paint with by using PmForeColor() and PmBackColor(). The
window truly fills the screen: any rounded corners are made square and if the
window is on the main screen then the Menu Bar is hidden. The screen occupies
the content area of the window; the window's frame (one-pixel black line border
and title bar) is off that screen, but will appear on other screens that form
contiguous parts of your desktop. The elegant solution to this, which perhaps
someone will implement, would be to define a new window type that has no frame.
GDDisposeWindow(window) closes and discards a color window, disposing of any
palette or color table, generally undoing whatever GDOpenWindow1 did.
AddExplicitPalette(window) adds a palette to a color window or GWorld with all
the colors marked as pmExplicit. This allows you to use PmForeColor() and
PmBackColor() to specify the value you want poked into each pixel by QuickDraw
operations, e.g. EraseRect() and DrawString().
RemovePalette(window) disposes of the palette created by AddExplicitPalette.
SwapWindowExplicitMode(window,&explicit) swaps the contents of the Boolean
argument with the "explicit" bit (bit 14 of the ctFlags field) in the color
table. The use of this bit is documented in "VideoToolbox:Notes:CopyBits
slavishly". After much experimentation I decided that it's not useful, but I
leave this routine here for others that wish to experiment. Note that when
GDOpenWindow() creates a window, the window shares the color table belonging to
the device, so calling SwapWindowExplicitMode() modifies the shared table, i.e.
the device's color table is modified. You should restore it by calling
MakeColorTableExplicit() again. Failing to restore it will have cosmetic
aftereffects, even after your application quits. The most obvious aftereffect is
that documents in Word will be largely gray.
GetBitMapPtr(window) returns a pointer to the window's bitmap or pixmap.
IsGWorldPtr(window) returns true only if the window is a GWorldPtr.
COMMENTS:
Please read "VideoToolbox:Notes:CopyBits slavishly". QuickDraw likes to
pick a bunch of good colors and stuff them in the clut, in essentially random
order, except that white is first and black is last. It wants you to specify any
desired color as an RGB triplet and then it picks the mysterious clut index that
would provide the closest match. If you're processing grayscale images, then
QuickDraw's approach involves a lot of overhead involving inverse color tables,
and makes the numbers stored in your pixels meaningless (unless you look them up
in the associated color table or palette).
The philosophy of the VideoToolbox is to bypass QuickDraw's color model, and
work explicitly with the numbers that are stored in your pixels.
SetPixelsQuickly will efficiently poke (or peek) the numbers in your PixMap.
However, if you want to use QuickDraw's handy drawing operations, especially
EraseRect() and DrawString() then you need a way to specify the foreground and
background colors. AddExplicitPalette() gives your window a palette in which all
the colors are marked as pmExplicit. This tells the palette manager to use your
arguments to PmForeColor() and PmBackColor() literally.
I suggest that you control the clut by calling GDUncorrectedGamma() and
GDSetEntries(), since these calls directly control the video device driver,
bypassing the Color Manager. Since the Color and Palette Managers don't know
that you've changed the color environment they can't react to it, and will
passively let you continue to specify colors by their clut index. For example,
the Palette Manager religiously believes that the first clut entry should be
white and the last one black, and it will change them back to those values if
you change them and it finds out about it. If you use the Color Manager
SetEntries call then the Paletter Manger WILL find out because a record is made
in the ColorTable. Calling GDSetEntries() bypasses the Color Manager. Instead,
the video device driver writes directly to the clut and the ColorTable is not
modified. Of course, this means that you should ignore the ColorTable since it
will no longer reflect the contents of the clut.
Every time you access the stdio package, e.g. printf or getch(), THINK C will
move the console window to the front, which may obscure your window. You can
bring your window back to the front by calling BringToFront() or SelectWindwo().
NOTE:
Tom Busey (busey@indiana.edu) writes: "I'm using an 8-bit SuperMac ColorCard
that a used computer dealer gave me when I ordered a Toby card. I discovered
that the status and control calls for GDUncorrectedGamma return -17 and -18
respectively, which means that the driver doesn't support different gammas.
GDUncorrectedGamma returns an error message, but GDOpenWindow doesn't use the
error message or pass it back to the calling program. I'm wondering if there are
people using GDOpenWindow who think that they are getting a linear gamma but who
are actually getting an error message and not learning about it."
Tom's facts are right, but he needn't worry. A few video drivers, e.g.
Radius PowerView, and apparently the SuperMac ColorCard, don't implement gamma
tables at all, but the error from GDUncorrectedGamma is probably not a concern.
The real test is to run TimeVideo. TimeVideo does a write-and-read-back test of
the clut of your video card. If that test passes then you can safely conclude
that there's no gamma translation going on. So, as nearly every document in the
VideoToolbox says: run TimeVideo and read the report.
Here's how gamma tables work. According to the Apple manual (Designing
Cards and Drivers), the values in the rgb triplets that you supply in a
cscSetEntries call to the video driver are first translated via the gamma table
(each r,g, and b component separately) before being loaded into the CLUT
hardware table. Most drivers maintain a gamma table internally (in computer
memory) and allow you to get and set it via the GDGetGamma and GDSetGamma calls.
A few video drivers (Radius PowerView, SuperMac ColorCard) don't support gamma
tables. They load your rgb values directly into the CLUT, without translation.
However, for users of the VideoToolbox that's usually fine, since that's exactly
the behavior that we routinely request by calling GDUncorrectedGamma. Of course,
if you want to load a custom gamma table, other than the identity
transformation, then you'll be calling GDSetGamma, and you should make sure it
does not return an error. (Alas, the Radius PowerView driver more or less
ignores the set- and get-gamma requests--GDGetGamma returns a table that's all
zeroes--but the driver fails to report an error. I wrote to the Radius
programmer a year ago, but they're no longer interested in working on that
product.)
PROBLEM:
How can I tell whether I've got a CGrafPtr or a GWorldPtr? (In one case I'll call
GetGWorldDevice, in the other case I'll get max device.)
I noticed that the portVersions are 0xc001 and 0xc000. Should I use that to tell?
ANSWER FROM APPLE DEVSUPPORT (8/93):
You can use GetGWorldDevice() on GWorldPtr, GrafPort or CGrafPort. Use
TestDeviceAttibute() to test if the returned GDHandle is a "real" screen or not.
Also, you should refer to the tech note “RowBytes Revealed II” (available on the
June Developer CD) which states:
You'll notice in Figure 1 that the portVersion field of a cGrafPort coincides
with the location of the rowBytes field of a grafPort. Remember, a cGrafPort has
the same size as a grafPort. During debugging, you can use the same information
that CopyBits uses to identify cGrafPorts.
If you use a grafPort template to display memory for an unknown grafPort, you
can tell if it is a cGrafPort because the rowBytes will be equal to 0xC000. The
0xC corresponds to the two high bits being set in the portVersion field of a
cGrafPort. Since these bits can not be set in a grafPort, you know you have a
cGrafPort. In addition, if the bottom bit of the portVersion field is set, then
it is a gWorld. Thus, if your rowBytes field has a value of 0xC001, then you
know you have a gWorld.
CONCLUSION:
This advice is implemented in the routine IsGWorldPtr(window).
HISTORY:
12/88 dgp wrote it
8/5/89 added call to GDUncorrectedGamma, so I couldn't forget.
8/15/89 dgp trivia
3/20/90 dgp make compatible with MPW C.
3/29/90 dgp changed declared returned type from WindowPtr to CWindowPtr, which
is what it's really been all along. Same change to argument of
GDDisposeWindow(). The new offscreen GWorld calls for the first time
make it easier to honestly declare one's windows as color rather
than pretending they're not.
8/24/91 dgp Made compatible with THINK C 5.0.
2/1/92 dgp Made optional the device argument to GDDisposeWindow(). If it's
NULL, then it will be determined automatically from window.
2/3/93 dhb Extracted AddExplicitPalette from GDOpenWindow.
2/21/93 dgp HideMenuBar if window is on main screen.
2/23/93 dgp AddExplicitPalette() returns immediately unless it receives a color
window.
Added GDOpenWindow1() and GDDisposeWindow1(), which both use
a WindowPtr, instead of a less convenient CWindowPtr.
3/5/93 dgp Added calls to UnclipScreen() and RestoreScreenClipping(), so the window
now truly fills the whole screen. Edited GDOpenWindow() for clarity.
3/7/83 dgp Added calls to GDSaveGamma(device) and GDRestoreGamma(device).
4/16/93 dgp Cosmetic editing.
5/22/93 dgp Added RemovePalette(), but didn't test it.
1/27/94 dgp Cosmetic editing.
3/5/94 dgp Decided that RemovePalette() works fine now.
6/8/94 dgp AddExplicitPalette now calls the new MakeColorTableExplicit(), which
sets the Color Table ctFlags to indicate that
the Color Table refers explicitly
to the explicit palette. This tells CopyBits to treat
the pixels as numbers, not indices.
6/13/94 dgp In response to query by David Brainard I now document above
the obscure fact that GDOpenWindow's frame will appear on
other screens that are contiguous parts of the desktop.
8/11/94 dhb & dgp David Brainard discovered that MakeColorTableExplicit(), which
is called by AddExplicitPalette, which is called by GDOpenWindow1, was affecting
not just the new window's color table, but was also affecting the device's color
table (because they share the same color table), and that the device's color
table was not restored. "The symptom is that if you subsequently launch
Microsoft Word, the background of the text window takes on a strange color
(grey) in regions where there is text," and the problem persists until reboot.
The solution is to give our window its own color table, which we can
safely modify.
8/12/94 dhb & dgp on 8/11 denis inadvertently introduced a bug into GDDisposeWindow1,
moving the call to GetWindowDevice() to a point after the window
was disposed of. David fixed it, moving the call back where it belonged.
8/14/94 dgp GDOpenWindow1 now gets the color table from the window's device instead
of the main device.
8/17/94 dgp make color table NOT explicit when GDDisposeWindow1 is called.
9/5/94 dgp removed assumption in printf's that int==short.
10/10/94 dgp GDOpenWindow1 now associates correct device's color table with window,
not MainDevice's.
10/24/94 dgp GDOpenWindow1 returns NULL if there's no driver associated with the device.
10/25/94 dgp Added GDGrayColorTable(device), which gives the device a standard gray color table.
11/2/94 dgp Leave the explicit bit alone. For the adventurous I provide the
MakeColorTableExplicit() routine and documentation in
VideoToolbox:Notes:"CopyBits slavishly".
11/17/94 dgp renamed IsWindow to IsGrafPtr. Renamed IsOffScreen to IsGWorldPtr.
4/11/95 dgp Fixed assertion failure in GDGrayWindow; the rsrc id of the 2-bit gray ramp is 2,
not 32+2.
4/11/95 dgp transferred some documentation of IsGWorldPtr from GetScreenDevice.c to above.
3/8/95 dgp GDOpenWindow1()'s call to GDGrayColorTable() causes the
window frame to become orange. I don't understand why, but it's only a cosmetic bug,
so i'm ignoring it for the moment.
*/
#include "VideoToolbox.h"
#define MAKE_COLOR_TABLE 0
WindowPtr GDOpenWindow1(GDHandle device)
{
return (WindowPtr)GDOpenWindow(device);
}
void GDDisposeWindow1(WindowPtr window)
{
GDDisposeWindow((CWindowPtr) window);
}
CWindowPtr GDOpenWindow(GDHandle device)
{
CWindowPtr window;
Rect r;
GDHandle oldDevice;
if(device==NULL || (*device)->gdRefNum==0)return NULL;
r=(*device)->gdRect; // rect of desired screen in global coordinates
GDSaveGamma(device);
GDUncorrectedGamma(device);
UnclipScreen(device);
GDGrayColorTable(device);
oldDevice=GetGDevice();
SetGDevice(GetMainDevice()); // Needed for window to work properly.
window=(CWindowPtr)NewCWindow(NULL,&r,"\p",TRUE,plainDBox,(WindowPtr) -1L,0,123L);
(*window->portPixMap)->pmTable=(**(**device).gdPMap).pmTable;
SetGDevice(oldDevice);
AddExplicitPalette((WindowPtr)window);
return window;
}
void GDGrayColorTable(GDHandle device)
// give the device a standard gray color table
{
ColorTable **table;
PixMap **pm;
int id;
if(device==NULL)return;
pm=(**device).gdPMap;
table=(**pm).pmTable;
id=(**pm).pixelSize;
if(id>2)id+=32;
if((**device).gdType==clutType && (**table).ctSeed!=id){
// Give the device a standard gray-ramp color table
table=GetCTable((**pm).pixelSize+32); // gray ramp
assert(table!=NULL);
assert((**(**pm).pmTable).ctSize==(**table).ctSize);
memcpy(*(**pm).pmTable,*table,8+((**table).ctSize+1)*sizeof(ColorSpec));
DisposeHandle((Handle)table);
table=(**pm).pmTable;
(**table).ctFlags|=0x8000; // mark as belonging to a device
GDeviceChanged(device);
}
}
void GDDisposeWindow(CWindowPtr window)
// Dispose of window and palette and restore the screen's clut and clipping.
{
GDHandle device;
if(window==NULL)return;
RemovePalette((WindowPtr)window);
#if MAKE_COLOR_TABLE
DisposHandle((Handle)(*((CGrafPtr)window)->portPixMap)->pmTable);
#endif
device=GetWindowDevice((WindowPtr)window);
DisposeWindow((WindowPtr)window);
if(device==NULL)return;
GDRestoreGamma(device);
GDRestoreDeviceClut(device);
RestoreScreenClipping(device);
}
void AddExplicitPalette(WindowPtr window)
// Create a palette for the color window and mark all the entries as explicit.
// Copy the entries from the window's device.
{
GDHandle device;
CTabHandle ct;
PaletteHandle palette;
int colors;
#if MAKE_COLOR_TABLE
int i,error;
#endif
if(window==NULL)return;
if(((CGrafPtr)window)->portVersion>=0) return; // Not a color window, return.
device=GetWindowDevice(window);
if(device==NULL)PrintfExit(
"AddExplicitPalette: window has no device! %s line %d.\n",__FILE__,__LINE__);
ct=(**(**device).gdPMap).pmTable;
colors=(*ct)->ctSize+1;
#if MAKE_COLOR_TABLE
error=HandToHand((Handle *)&ct);
if(error)PrintfExit("%s line %d: error %d in copying color table\n"
,__FILE__,__LINE__,error);
(*ct)->ctFlags &= 0x7fff; // clear "device" bit
for(i=0;i<colors;i++) (*ct)->ctTable[i].value=i;
(*ct)->ctSeed=GetCTSeed();
(*((CGrafPtr)window)->portPixMap)->pmTable=ct;
#endif
palette=NewPalette(colors,ct,pmExplicit+pmTolerant,0);
SetPalette(window,palette,0);
}
/*
RemovePalette may look dangerous. I worried that the Window or
Palette Manager might become confused if it later tries to access the
window's palette, which no longer exists. However, by trial and error
I've found that this works fine, and that my attempts to make explicit the
fact that the palette is gone, e.g. by calling SetPalette(window,NULL,0),
all produced crashes. I conclude that the Palette or Window Manager monitors
the calls to DisposePalette and thus knows that the palette is gone.
*/
void RemovePalette(WindowPtr window)
{
if(window==NULL)return;
DisposePalette(GetPalette(window));
}
void SwapWindowExplicitMode(CWindowPtr window,Boolean *explicit)
// Get and set bit 14 of the ctFlags field of the window's color table.
// This is only relevant to a CopyBits from an offscreen
// graphics environment, be it PixMap or GWorld, to an onscreen window.
// See Inside Mac VI, page 20-17. To get the full story see "CopyBits slavishly" in
// VideoToolbox:Notes.
{
int i,ok;
ColorTable **ct;
Boolean oldExplicit;
if(window==NULL)return;
// If it's a GWorldPtr then we must lock the pixels to access the pixmap.
if((window->portVersion&0xc001)==0xc001){
ok=LockPixels(GetGWorldPixMap(window));
if(!ok)return;
}
ct=(*window->portPixMap)->pmTable;
oldExplicit=((*ct)->ctFlags&0x4000)!=0;
if(*explicit){
(*ct)->ctFlags|=0x4000;
for(i=(*ct)->ctSize;i>=0;i--)(*ct)->ctTable[i].value=i;
}else{
(*ct)->ctFlags&=~0x4000;
}
*explicit=oldExplicit;
}
// CAUTION: The PixMap handles are not locked. So don't move memory. The
// returned pointers will become invalid as soon as you call any routine
// that moves memory. CopyBits and CopyBitsQuickly are ok.
BitMap *GetBitMapPtr(CWindowPtr window)
{
BitMap *bits;
int ok;
PixMapPtr *pm;
if(IsGWorldPtr(window)){
// It's a GWorldPtr, lock the pixels, return pixmap ptr.
ok=LockPixels(GetGWorldPixMap((GWorldPtr)window));
if(!ok)return NULL;
pm=GetGWorldPixMap((GWorldPtr)window);
// HLock((Handle)pm);
bits = (BitMap *)*pm;
}else if(!IsGrafPtr(window)){
pm=window->portPixMap;
// HLock((Handle)pm);
bits = (BitMap *)*pm;
}else{
bits = &((WindowPtr)window)->portBits;
}
return bits;
}
Boolean IsGWorldPtr(CWindowPtr window) // Is it a GWorldPtr?
{
return (window->portVersion&0xc001) == 0xc001;
}
Boolean IsGrafPtr(CWindowPtr window) // Is it a WindowPtr?
{
return window->portVersion>=0;
}